package com.gd.iot.energy.util;


import cn.hutool.json.JSONUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.UUID;

/**
 * jwt工具
 * @author kris
 */
public class CustomTokenJjwtUtil {
    private CustomTokenJjwtUtil() {
    }

    /**
     * 本地配置文件中加密的密文
     */
    private static final String STRING_KEY = "IOTEnergy@2020";

    /**
     * 生成token
     */
    public static <T> String createToken(T object) {
        return createJwt(getStringId(), JSONUtil.toJsonStr(object));
    }

    /**
     * 生成token
     *
     * @param id      随机数
     * @param subject JWT的主体
     * @return java.lang.String
     **/
    public static String createJwt(String id, String subject) {
        // 指定签名的时候使用的签名算法，也就是header那部分，jjwt已经将这部分内容封装好了。
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        // 生成JWT的时间
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);

        /* 下面就是在为payload添加各种标准声明和私有声明了
         这里其实就是new一个JwtBuilder，设置jwt的body
         如果有私有声明，一定要先设置这个自己创建的私有的声明，这个是给builder的claim赋值，一旦写在标准的声明赋值之后，就是覆盖了那些标准的声明的
         设置jti(JWT ID)：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
         iat: jwt的签发时间
         sub(Subject)：代表这个JWT的主体，即它的所有人，这个是一个json格式的字符串，可以存放什么userid，roldid之类的，作为什么用户的唯一标志。
         设置签名使用的签名算法和签名使用的秘钥
        */
        JwtBuilder builder = Jwts.builder()
                .setId(id)
                .setIssuedAt(now)
                .setSubject(subject)
                .signWith(signatureAlgorithm, STRING_KEY);
        return builder.compact();
    }

    /**
     * 生成随机数，回避重放攻击
     *
     * @return java.lang.String
     **/
    private static String getStringId() {
        return UUID.randomUUID().toString();
    }


    /**
     * 解密jwt
     *
     * @param jwt token
     * @return Claims
     */
    private static Claims parseJWT(String jwt) {
        //得到DefaultJwtParser,设置签名的秘钥,设置需要解析的jwt
        return Jwts.parser().setSigningKey(STRING_KEY).parseClaimsJws(jwt).getBody();
    }

    /**
     * 获取用户信息
     **/
    public static <T> T getPayload(String jwt,Class<T> clazz) {
        Claims claims = parseJWT(jwt);
        claims.getSubject();
        return JSONUtil.toBean(claims.getSubject(), clazz);
    }

}
